vimfandomcom-20200223-history
Convert between hex and decimal
This tip shows how to convert numbers from hexadecimal to decimal, and the reverse. A variety of methods are given, including some simple commands you can enter, and some scripts to easily replace hex numbers with decimal, or to replace decimal with hex. Handling percent-encoded text is also discussed, and there are links to tips showing how to edit a binary file in hex. Commands Occasional conversions can be performed by entering commands. In Vim, put the cursor on 0x12345 and type :echo then Space Ctrl-R Ctrl-W Enter. That will execute :echo 0x12345 which displays 74565 (decimal equivalent of hex 12345). An example of converting decimal to hex would be to enter :echo printf('%x',74565) which displays 12345 (hex equivalent of decimal 74565). In addition, the expression register can be used to enter converted numbers while typing. In insert mode, press Ctrl-R then = then the expression wanted, then press Enter. The value of the expression is inserted, and you will remain in insert mode. For example, =0x09ab will insert 2475, and =printf('0x%04x',2475) will insert 0x09ab. In normal mode, type ga to display the decimal and hex values for the character under the cursor, or type g8 to display the hex bytes for a UTF-8 character. The following commands illustrate other simple techniques to convert strings to numbers which are displayed in decimal (the :echo is just for illustration; these techniques would be used in a script). The first shows that adding zero to a string converts the string to a number. The following convert decimal numbers to hex strings. Copying a hex number as decimal With the following mapping, you can put the cursor on a hex number and press \h (assuming the default backslash leader) to yank the value of the hex number (using :let means the equivalent decimal string is copied). You can then move the cursor elsewhere and press p to paste the decimal value. nnoremap \h :let @@= Alternatively, you can use a global variable to avoid using a register. With these mappings, \h will yank a hex value, and \p will paste the decimal string: nnoremap \h :let Value= nnoremap \p :if exists('Value')normal i=Value:endif User commands Put the following in your vimrc to define user commands to convert between hex and decimal. You can convert a number entered on the command line, or all numbers in selected text. command! -nargs=? -range Dec2hex call s:Dec2hex(, , ) function! s:Dec2hex(line1, line2, arg) range if empty(a:arg) if histget(':', -1) =~# "^'<,'>" && visualmode() !=# 'V' let cmd = 's/\%V\<\d\+\>/\=printf("0x%x",submatch(0)+0)/g' else let cmd = 's/\<\d\+\>/\=printf("0x%x",submatch(0)+0)/g' endif try execute a:line1 . ',' . a:line2 . cmd catch echo 'Error: No decimal number found' endtry else echo printf('%x', a:arg + 0) endif endfunction command! -nargs=? -range Hex2dec call s:Hex2dec(, , '') function! s:Hex2dec(line1, line2, arg) range if empty(a:arg) if histget(':', -1) =~# "^'<,'>" && visualmode() !=# 'V' let cmd = 's/\%V0x\x\+/\=submatch(0)+0/g' else let cmd = 's/0x\x\+/\=submatch(0)+0/g' endif try execute a:line1 . ',' . a:line2 . cmd catch echo 'Error: No hex number starting "0x" found' endtry else echo (a:arg =~? '^0x') ? a:arg + 0 : ('0x'.a:arg) + 0 endif endfunction The above defines user commands :Dec2hex and :Hex2dec that will either display the result of converting a number that you enter, or will convert all numbers in selected text. A decimal number is a word consisting only of decimal digits, while a hex number consists of "0x" followed by one or more hex digits. If no argument is entered with these commands, a range may be specified. The default range is the current line. A visual selection (character, line, or block) can also specify a range. When using a visual block (selection starts with Ctrl-V, or Ctrl-Q if Ctrl-V is used for paste), only numbers inside the block are converted. Example commands: This version handles up to 32-bit long integers. An extended version of this script that works for arbitrary sized integers is available as a plugin on Github. Converting strings Following are some methods for working with percent-encoded text, and for showing ASCII characters in hex. " Convert current line to percent-encoded hex for disallowed punctuation. " Example: line "A/C123D\E" is converted to "A%2FC%5B123%5DD%5CE". nnoremap h :s@\([;(){}\\+ ,\-><\|=%&^\\/"']\)@\='%'.printf('%02X',char2nr(submatch(1)))@g " Convert percent-encoded hex in current line to text (reverse of above). nnoremap H :s@%\(\x\x\)@\=nr2char('0x'.submatch(1))@g " Convert each ASCII character in a string to hex bytes. " Example: ":Str2hex ABC 123" displays "41 42 43 20 31 32 33". command! -nargs=* Str2hex echo Str2hex() function! Str2hex(arg) return join(map(split(a:arg, '\zs'), 'printf("%02x", char2nr(v:val))')) endfunction General functions A script could use the following functions for conversions between decimal and hex. " Return hex string equivalent to given decimal string or number. function! Dec2hex(arg) return printf('%x', a:arg + 0) endfunction " Return number equivalent to given hex string ('0x' is optional). function! Hex2dec(arg) return (a:arg =~? '^0x') ? a:arg + 0 : ('0x'.a:arg) + 0 endfunction Sometimes one just needs to know the value of decimal/hexadecimal value, without changing the text. Put the following in your vimrc to define user command 'gn' to print the number under the cursor converted to hex/decimal (similar to built-in command 'ga' and 'g8' for ASCII character under the cursor): nnoremap gn :call DecAndHex(expand("")) function! DecAndHex(number) let ns = '[.,;:"<>()^_lL]' " number separators if a:number =~? '^' . ns. '*-+\?\d\+' . ns . '*$' let dec = substitute(a:number, '^0-9+-*\(+-\?\d\+\).*','\1',) echo dec . printf(' -> 0x%X, -(0x%X)', dec, -dec) elseif a:number =~? '^' . ns. '*\%\(h\|0x\|#\)\?\(\x\+\)' . ns . '*$' let hex = substitute(a:number, '.\{-}\%\(h''\|0x\|#\)\?\(\x\+\).*','\1',) echon '0x' . hex . printf(' -> %d', eval('0x'.hex)) if strpart(hex, 0,1) =~? '89a-f' && strlen(hex) =~? '2\|4\|6' " for 8/16/24 bits numbers print the equivalent negative number echon ' ('. float2nr(eval('0x'. hex) - pow(2,4*strlen(hex))) . ')' endif echo else echo "NaN" endif endfunction Numbers containing character A-F or prefixed with '0x', 'h' or '#' are treated as hexadecimal values: Using external programs *Fix or delete this section. *The following is from old tip 772. It does not seem helpful, but we should discuss the menus somewhere so I am keeping the text for a while. This example creates a menu for conversions using the bc calculator which is a standard utility on many Unix-based systems. Visually select the number (without leading '0x'), right click the selection, and select from the popup menu to transform the number. vmenu 1.220 PopUp.&nr2hex :exec("!echo \\"obase=16;".@*."\\" \| bc -l -q ") vmenu 1.220 PopUp.hex&2nr :exec("!echo \\"ibase=16;".toupper(@*)."\\" \| bc -l -q ") More is needed to make it work. I had to do the following on a Linux system, but I suspect a setting regarding register * is also being used (it assumes that the selected text is in the * register). set mousemodel=popup vmenu 1.220 PopUp.&nr2hex :exec '!echo "obase=16;'.@*.'" \| bc -l -q ' vmenu 1.220 PopUp.hex&2nr :exec '!echo "ibase=16;'.toupper(@*).'" \| bc -l -q ' See also *Hex dump editing or displaying binary files in hex *Improved hex editing automating some of the procedures to edit binary files in hex *How to convert from decimal to hexManual hex to decimal conversion * plugin to convert to/from various numeric bases *Convert Hexadecimal to Decimal Number online tool to convert hex to dec *From one to another number system, ''article related to creating computer program for conversion of number from one to another number system with source code written in C# Comments